// 1. 定义函数类型：约束“接收两个number参数，返回number”的函数
type BinaryNumberFn = (a: number, b: number) => number;

// 2. 原计算函数（带类型标注，确保输入输出类型正确）
const add: BinaryNumberFn = (a, b) => a + b;
const multiply: BinaryNumberFn = (a, b) => a * b;

// 3. 日志装饰器：用泛型约束输入函数类型为BinaryNumberFn
function logDecorator(fn: BinaryNumberFn): BinaryNumberFn {
  // 返回的新函数与原函数类型完全一致（TS自动推断）
  return function(a: number, b: number): number {
    // 装饰逻辑：参数类型明确，不会出现非数字
    console.log(`输入参数：${a}, ${b}`);
    // 执行原函数：fn类型被约束，可安全调用
    const result = fn(a, b);
    // 装饰逻辑：result类型为number，无需担心类型错误
    console.log(`执行结果：${result}`);
    return result;
  };
}

// 4. 使用装饰器（装饰后函数仍为BinaryNumberFn类型，类型安全）
const decoratedAdd = logDecorator(add);
const decoratedMultiply = logDecorator(multiply);

// 测试：TS编译时检查类型
decoratedAdd(2, 3); // 正确：输出日志，返回5
// decoratedAdd('2', 3); // 错误：TS编译报错，参数“2”应为number类型
decoratedMultiply(4, 5); // 正确：输出日志，返回20

// ========== 新增：装饰器小案例（类装饰器 + 方法装饰器） ==========
// 注意：运行需在 tsconfig.json 中启用 "experimentalDecorators": true，
// 或使用你项目中的 run-ts.js（已注册 ts-node）。

// 类装饰器：封印类（示例用）
function sealed(constructor: Function) {
  Object.seal(constructor);
  Object.seal(constructor.prototype);
}

// 方法装饰器：在执行前后打印日志
function log(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor
) {
  console.log(target);
  console.log(propertyKey);
  console.log(descriptor);
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`[log] 调用 ${propertyKey}，参数：`, args);
    const result = original.apply(this, args);
    console.log(`[log] ${propertyKey} 返回：`, result);
    return result;
  };
  return descriptor;
}

// 使用装饰器
@sealed
class Calculator {
  @log
  add(a: number, b: number) {
    return a + b;
  }

  @log
  multiply(a: number, b: number) {
    return a * b;
  }
}

// 测试
const calc = new Calculator();
calc.add(2, 3);       // 控制台会先输出调用参数，再输出结果
calc.multiply(4, 5);


// 装饰器函数，它的第一个参数是目标类
function classDecorator(target) {
    target.hasDecorator = true
  	return target
}

// 将装饰器“安装”到Button类上
@classDecorator
class Button {
    // Button类的相关逻辑
}
// 验证装饰器是否生效
// console.log('Button 是否被装饰了：', Button.hasDecorator)

/**
 * 性能监控装饰器（TS 版）
 * @template T - 泛型：约束被装饰函数的类型（参数数组 + 返回值）
 * @param {T} func - 被装饰的函数，类型由泛型 T 自动推断
 * @returns {T} 增强后的函数，类型与原函数完全一致
 */
function performanceDecorator<T extends (...args: any[]) => any>(func: T): T {
  // 用类型断言确保返回值类型与原函数一致
  return function (...args: Parameters<T>): ReturnType<T> {
    const startTime = Date.now();
    // 原函数的 this 指向和参数类型由 TS 自动校验
    const result = func.apply(this, args);
    const costTime = Date.now() - startTime;
    
    console.log(`[性能监控] ${func.name}：`);
    console.log(`- 参数：${JSON.stringify(args)}`);
    console.log(`- 返回值：${JSON.stringify(result)}`);
    console.log(`- 耗时：${costTime}ms`);
    
    return result;
  } as T;
}

// 测试 1：装饰「计算数组总和」的函数（TS 自动推断参数为 number[]，返回值为 number）
function calculateSum(arr: number[]): number {
  return arr.reduce((total, cur) => total + cur, 0);
}
const enhancedCalculateSum = performanceDecorator(calculateSum);
// ✅ 正确调用：参数为 number[]
enhancedCalculateSum([1, 2, 3, 4]); 
// ❌ 错误调用：TS 编译报错（参数应为 number[]，而非 string[]）
// enhancedCalculateSum(["1", "2"]);

// 测试 2：装饰「格式化时间」的函数（TS 自动适配不同函数类型）
function formatTime(date: Date): string {
  return date.toLocaleString();
}
const enhancedFormatTime = performanceDecorator(formatTime);
// ✅ 正确调用：参数为 Date
enhancedFormatTime(new Date()); 
// ❌ 错误调用：TS 编译报错（参数应为 Date，而非 string）
// enhancedFormatTime("2024-05-01");